Repository Public
1// Auteur : Simon-Pierre Boucher — contact@spboucher.ai2// /api/admin/team/[id] — gestion d'un compte admin (super_admin seulement) :3// rôles, activation, nom, courriel, réinitialisation du mot de passe.4// Garde-fous : impossible de se désactiver soi-même ou de retirer le dernier5// super_admin actif.6import { NextRequest, NextResponse } from "next/server";7import {8 findAdminById,9 listAdmins,10 setAdminPassword,11 updateAdmin,12} from "@/lib/comms/db";13import {14 getAdminSession,15 isSuperAdmin,16 parseRoles,17 ADMIN_ROLES,18} from "@/lib/comms/admin-auth";1920function lastActiveSuperAdmin(targetId: number): boolean {21 const remaining = listAdmins().filter(22 (a) => a.id !== targetId && a.active && parseRoles(a.roles).includes("super_admin"),23 );24 return remaining.length === 0;25}2627export async function PATCH(28 req: NextRequest,29 { params }: { params: Promise<{ id: string }> },30) {31 const session = await getAdminSession();32 if (!session)33 return NextResponse.json({ error: "Non autorisé." }, { status: 401 });34 if (!isSuperAdmin(session))35 return NextResponse.json({ error: "Réservé au super administrateur." }, { status: 403 });36 const id = Number((await params).id);37 const target = Number.isInteger(id) ? findAdminById(id) : undefined;38 if (!target)39 return NextResponse.json({ error: "Compte introuvable." }, { status: 404 });4041 const body = (await req.json().catch(() => null)) as {42 display_name?: string;43 email?: string | null;44 roles?: string[];45 active?: boolean;46 password?: string;47 } | null;48 if (!body)49 return NextResponse.json({ error: "Requête illisible." }, { status: 400 });5051 if (body.roles !== undefined) {52 const roles = body.roles.filter((r) => r in ADMIN_ROLES);53 if (!roles.length)54 return NextResponse.json({ error: "Au moins un rôle requis." }, { status: 422 });55 if (56 parseRoles(target.roles).includes("super_admin") &&57 !roles.includes("super_admin") &&58 lastActiveSuperAdmin(target.id)59 )60 return NextResponse.json(61 { error: "Impossible de retirer le dernier super administrateur." },62 { status: 422 },63 );64 updateAdmin(target.id, { roles });65 }66 if (body.active !== undefined) {67 if (target.id === session.id && !body.active)68 return NextResponse.json(69 { error: "Impossible de désactiver votre propre compte." },70 { status: 422 },71 );72 if (73 !body.active &&74 parseRoles(target.roles).includes("super_admin") &&75 lastActiveSuperAdmin(target.id)76 )77 return NextResponse.json(78 { error: "Impossible de désactiver le dernier super administrateur." },79 { status: 422 },80 );81 updateAdmin(target.id, { active: body.active });82 }83 if (body.display_name !== undefined) {84 const dn = body.display_name.trim().slice(0, 120);85 if (!dn)86 return NextResponse.json({ error: "Nom d'affichage requis." }, { status: 422 });87 updateAdmin(target.id, { display_name: dn });88 }89 if (body.email !== undefined)90 updateAdmin(target.id, {91 email: body.email ? body.email.trim().slice(0, 200) : null,92 });93 if (body.password !== undefined) {94 if (body.password.length < 8)95 return NextResponse.json(96 { error: "Mot de passe trop court (8 caractères minimum)." },97 { status: 422 },98 );99 // Change le mot de passe ET invalide toutes les sessions du compte100 // (l'empreinte pwv du jeton ne correspond plus).101 setAdminPassword(target.id, body.password);102 }103 return NextResponse.json({ ok: true });104}105